﻿namespace Sai.Core
{
	using System;
	using System.IO;
	using System.Xml.Serialization;
	using Sai.Core.Reporting;

	public class ProductReleaseProjectBuilder
	{
        public ProductReleaseProject CreateDefault()
        {
            ProductReleaseProject project = new ProductReleaseProject
            {
                Name = "New Project",
                CleanOutput = true,
                OutputFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
                ReportFormat = ReportFormat.Html,
                ReportOnAdditions = false,
                ReportOnChanges = true,
                ReportOnRemovals = true,
                ReportOnObsolete = true,
                Version = "1.0.0.0"
            };

            string folder = FindCustomReportLocation(project.ReportStyleName);

            this.FindStyle(project, folder);
            this.FindReportTransformations(project, folder);

            return project;
        }

		public ProductReleaseProject CreateFromFile(string fileName)
		{
			using (var reader = new StreamReader(fileName))
			{
				ProductReleaseProject project = this.CreateFrom(reader);
				project.FileName = fileName;

                // now fix up project paths...

				return project;
			}
		}

		public ProductReleaseProject CreateFrom(TextReader reader)
		{
            return ObjectFlattener<ProductReleaseProject>.Inflate(reader);
		}

		public ProductReleaseProject Create(string name, 
            Version appVersion, 
            string fromVersion, 
            string fromFolder, 
            string toVersion, 
            string toFolder, 
            string outputFolder, 
            ReportFormat format, 
            bool cleanOutput, 
            string sandcastleProject, 
            string topicId,
            bool reportOnRemovals,
            bool reportOnAdditions,
            bool reportOnChanges,
            bool reportOnObsolete)
		{
			ProductReleaseProject project = new ProductReleaseProject(appVersion)
				{
					Name = name,
					FromVersion = fromVersion,
					FromFolder = fromFolder,
					ToVersion = toVersion,
					ToFolder = toFolder,
					OutputFolder = outputFolder,
					ReportFormat = format,
					CleanOutput = cleanOutput,
					SandcastleProject = sandcastleProject,
					TopicId = topicId,
                    ReportOnRemovals = reportOnRemovals,
                    ReportOnAdditions = reportOnAdditions,
                    ReportOnChanges = reportOnChanges,
                    ReportOnObsolete = reportOnObsolete
				};

			string folder = FindCustomReportLocation(project.ReportStyleName);

            this.FindStyle(project, folder);
            this.FindReportTransformations(project, folder);
			
			return project;
		}

        public ProductReleaseProject Create(ProductReleaseProject existingProject, ReportFormat format)
        {
            ProductReleaseProject newProject = new ProductReleaseProject(existingProject.Version)
            {
                Name = existingProject.Name,
                FileName = existingProject.FileName,
                Version = existingProject.Version,
                FromVersion = existingProject.FromVersion,
                FromFolder = existingProject.FromFolder,
                ToVersion = existingProject.ToVersion,
                ToFolder = existingProject.ToFolder,
                OutputFolder = existingProject.OutputFolder,
                HeadTag = existingProject.HeadTag,
                HeadingText = existingProject.HeadingText,
                StyleTag = existingProject.StyleTag,
                FooterText = existingProject.FooterText,
                ReportFormat = format,
                CleanOutput = existingProject.CleanOutput,
                SandcastleProject = existingProject.SandcastleProject,
                TopicId = existingProject.TopicId,
                ReportOnRemovals = existingProject.ReportOnRemovals,
                ReportOnAdditions = existingProject.ReportOnAdditions,
                ReportOnChanges = existingProject.ReportOnChanges,
                ReportOnObsolete = existingProject.ReportOnObsolete
            };

            newProject.AddFromFiles(existingProject.FromAssemblies);
            newProject.AddToFiles(existingProject.ToAssemblies);

            string folder = FindCustomReportLocation(newProject.ReportStyleName);

            this.FindStyle(newProject, folder);
            this.FindReportTransformations(newProject, folder);

            return newProject;
        }

        public void FixProjectStyling(ProductReleaseProject project)
        {
            string folder = FindCustomReportLocation(project.ReportStyleName);

            this.FindStyle(project, folder);
            this.FindReportTransformations(project, folder);
        }

        private string FindCustomReportLocation(string reportStyleName)
        {
            string location = System.Reflection.Assembly.GetExecutingAssembly().Location;
            return Path.Combine(Path.GetDirectoryName(location), "Reporting", reportStyleName);
        }

        private void FindStyle(ProductReleaseProject project, string folder)
        {
            ReportStyleRegistry styleRegistry = new ReportStyleRegistry();

            styleRegistry.Add(new FileBasedStyleRepository(folder));
            styleRegistry.Add(new DefaultStyleRepository());

            project.ReportStyler = styleRegistry.Find(project.ReportStyleName);
        }

        private void FindReportTransformations(ProductReleaseProject project, string folder)
        {
            ReportTransformationRegistry transformationRegistry = new ReportTransformationRegistry();

            transformationRegistry.Add(new FileBasedReportTransformationRepository(folder));
            transformationRegistry.Add(new EmbeddedReportTransformationRepository());

            project.SummaryTransformer = transformationRegistry.Find(typeof(IProductReleaseDifference), project.ReportFormat);
            project.AssemblyTransformer = transformationRegistry.Find(typeof(IAssemblyDifference), project.ReportFormat);
            project.TypeTransformer = transformationRegistry.Find(typeof(ITypeDifference), project.ReportFormat);
            project.ListingTransformer = transformationRegistry.Find(typeof(ITypeListing), project.ReportFormat);
        }
	}
}
